package timing.ukulele.user.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.ShearCaptcha;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.context.annotation.Import;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import timing.ukulele.common.data.CaptchaResult;
import timing.ukulele.common.data.ResponseData;
import timing.ukulele.data.user.view.PasswordVO;
import timing.ukulele.facade.user.mvc.CommonControllerFacade;
import timing.ukulele.redisson.cache.CacheManager;
import timing.ukulele.share.Constant;
import timing.ukulele.user.config.properties.ForgotPasswordEmailProperties;
import timing.ukulele.user.model.MailBean;
import timing.ukulele.user.persistent.SysUser;
import timing.ukulele.user.service.SysUserService;
import timing.ukulele.user.util.DecryptUtil;
import timing.ukulele.web.controller.BaseController;

import java.util.List;

import static timing.ukulele.user.config.TopicConfig.EMAIL_CHANNEL;
import static timing.ukulele.user.config.TopicConfig.EMAIL_ROUTING;
import static timing.ukulele.user.constant.Constant.FORGOT_PASSWORD_CAPTCHA_PREFIX;

@RestController
@Slf4j
@Import(ForgotPasswordEmailProperties.class)
public class CommonController extends BaseController implements CommonControllerFacade {
    private final AmqpTemplate rabbitTemplate;
    private final CacheManager cacheManager;
    private final SysUserService service;
    private final ForgotPasswordEmailProperties passwordEmailProperties;

    public CommonController(AmqpTemplate rabbitTemplate, CacheManager cacheManager,
                            SysUserService service, ForgotPasswordEmailProperties passwordEmailProperties) {

        this.rabbitTemplate = rabbitTemplate;
        this.cacheManager = cacheManager;
        this.service = service;
        this.passwordEmailProperties = passwordEmailProperties;
    }

    /**
     * 生成验证码并缓存起来
     */
    @Override
    public ResponseData<CaptchaResult> getForgotCaptcha() {
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(130, 34, 4, 2);
        String code = captcha.getCode();
        this.cacheManager.set(FORGOT_PASSWORD_CAPTCHA_PREFIX + code, captcha.getCode(), 5 * 60);
        return ResponseData.success("获取验证码成功.", new CaptchaResult(null, null, captcha.getImageBase64Data()));
    }

    @Override
    public ResponseData<String> sendForgotPasswordEmailCode(String email, String code) {
        if (!StringUtils.hasText(email) || !StringUtils.hasText(code)) {
            return paraErrorResponse();
        }
        String cachedCode = this.cacheManager.get(FORGOT_PASSWORD_CAPTCHA_PREFIX + code);
        if (cachedCode == null)
            return failResponse(null, "验证码失效");
        if (!code.equalsIgnoreCase(cachedCode)) {
            return failResponse(null, "验证码错误");
        }
        boolean exists = this.service.lambdaQuery().eq(SysUser::getEmail, email).exists();
        if (!exists) {
            return errorResponse(null, "该邮箱不存在");
        }
        String key = Constant.REST_PASSWORD_EMAIL_CODE_CACHE_PREFIX + DigestUtils.md5DigestAsHex(email.getBytes());
        String existsKey = cacheManager.get(key);
        if (existsKey!=null)
            return errorResponse("验证已发送，15分钟内有效，请勿重复发送");
        MailBean bean = new MailBean();
        bean.setSubject(passwordEmailProperties.getSubject());
        bean.setToAccount(email);
        ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(130, 34, 6, 2);
        String cacheCode = captcha.getCode();
        cacheManager.set(Constant.REST_PASSWORD_EMAIL_CODE_CACHE_PREFIX + DigestUtils.md5DigestAsHex(email.getBytes()), cacheCode, 15 * 60);
        log.info("进入缓存的重置密码验证码为：" + cacheCode);
        bean.setContent(String.format(passwordEmailProperties.getContentTemplate(), cacheCode));
        rabbitTemplate.convertAndSend(EMAIL_CHANNEL, EMAIL_ROUTING, bean);
        return successResponse("验证码发送成功，请至您的邮箱中查看", "验证码发送成功，请至您的邮箱中查看");
    }

    @Override
    public ResponseData<String> passwordReset(PasswordVO vo) {
        String username = vo.getUsername();
        String newPwd = vo.getNewPwd();
        String email = vo.getEmail();
        String code = vo.getCode();
        if (!(StringUtils.hasText(newPwd) && StringUtils.hasText(email) && StringUtils.hasText(code) && StringUtils.hasText(username))) {
            return paraErrorResponse();
        }
        SysUser user = this.service.lambdaQuery().select(SysUser::getEmail, SysUser::getId).eq(SysUser::getUsername, username).one();
        if (user == null) {
            return failResponse(null, "用户不存在");
        }
        String userEmail = user.getEmail();
        if (!StringUtils.hasText(userEmail)) {
            return failResponse(null, "用户尚未绑定邮箱");
        }
        if (!userEmail.equalsIgnoreCase(email)) {
            return failResponse(null, "不是绑定的邮箱");
        }
        String key = Constant.REST_PASSWORD_EMAIL_CODE_CACHE_PREFIX + DigestUtils.md5DigestAsHex(email.getBytes());
        String cacheObject = cacheManager.get(key);
        if (cacheObject == null)
            return errorResponse(null, "验证正码已过期");
        log.info("缓存中的重置密码验证码为：" + cacheObject);
        if (!code.equalsIgnoreCase(cacheObject))
            return errorResponse(null, "验证码错误！");
        List<SysUser> list = this.service.lambdaQuery().eq(SysUser::getEmail, email).list();
        if (CollectionUtils.isEmpty(list)) {
            return errorResponse(null, "不存在该邮箱账号！");
        }
        if (list.size() > 1) {
            return errorResponse(null, "该邮箱存在多个账号！");
        }
        String dp = DecryptUtil.decryptPassword(newPwd);
        BCryptPasswordEncoder bpe = new BCryptPasswordEncoder(6);
        String pwd = bpe.encode(dp);
        this.service.lambdaUpdate().set(SysUser::getPassword, pwd).eq(SysUser::getEmail, email).update();
        cacheManager.del(key);
        return successResponse("密码重置成功");
    }
}
